#ifndef XDIVA_COMMANDSERVER_H
#define XDIVA_COMMANDSERVER_H

#include <QtCore/QObject>
#include <QtNetwork/QHostAddress>

#include <memory>

class CommandServer: public QObject {
	Q_OBJECT
public:
	/**
	 * @brief Initialize command server
	 * @attention NOT THREAD-SAFE!
	 *
	 * This method must be invoking before any thread spawn.
	 */
	static void initialize();
	/**
	 * @brief Get global instance
	 * @attention MUST call initialze() once first!
	 */
	static CommandServer & instance();

	/**
	 * @brief Listen on an address with a port
	 * @param address host address
	 * @param port listening port
	 * @return true if succeed
	 *
	 * Example:
	 * CommandServer::instance().listen( "127.0.0.1", 8000 );
	 */
	bool listen( const QHostAddress & address = QHostAddress::Any, quint16 port = 0U );

	/**
	 * @brief Ask a variable's type and address
	 * @note will block until responsed
	 * @param variableName the variable name
	 * @return a map, see below
	 * @throw ProtocolError on protocol error
	 *
	 * {
	 *   "<VARNAME>": "str",
	 *   "<VARTYPE>": "str",
	 *   "<ADDR>": "str",
	 * }
	 */
	QVariant ask( const QString & variableName );
	/**
	 * @brief Ask a variable's value
	 * @note will block until responsed
	 * @param variableName the variable name
	 * @return a map, see below
	 * @throw ProtocolError on protocol error
	 *
	 * {
	 *   "<VARNAME>": "str",
	 *   "<VALUE>": "str",
	 * }
	 */
	QVariant show( const QString & variableName );
	/**
	 * @brief Ask a variable's struct member
	 * @note will block until responsed
	 * @param variableName the variable name
	 * @return a map, see below
	 * @throw ProtocolError on protocol error
	 *
	 * {
	 *   "<CLASSNAME>": "str",
	 *   "<ATTRS>": [
	 *     {
	 *       "<VARNAME>": "str",
	 *       "<VARTYPE>": "str",
	 *     }, ...
	 *   ],
	 * }
	 */
	QVariant structure( const QString & className );
	/**
	 * @brief Ask if a variable is in scope
	 * @note will block until responsed
	 * @param variableName the variable name
	 * @return true if in scope, else return false
	 * @throw ProtocolError on protocol error
	 */
	QVariant scope( const QString & variableName );
	QVariant dangling( const QString & referenceName );
	/**
	 * @brief Tell debugger to continue
	 * @return don't care
	 */
	QVariant continue_();
	/**
	 * @brief Tell debugger to step in one frame
	 * @return don't care
	 */
	QVariant step();
	/**
	 * @brief Tell debugger to step to next instruction
	 * @return don't care
	 */
	QVariant next();
	/**
	 * @brief Tell debugger to step out one frame
	 * @return don't care
	 */
	QVariant over();
	/**
	 * @brief Ask current line number
	 * @note will block until responsed
	 * @return an integer
	 * @throw ProtocolError on protocol error
	 */
	QVariant line();

	/**
	 * @brief Send start command
	 * @note low-level command
	 */
	void start();
	/**
	 * @brief Send end command
	 * @note low-level command
	 */
	void end();
	/**
	 * @brief Send sync start command
	 * @note low-level command
	 */
	void syncStart();
	/**
	 * @brief Send sync end command
	 * @note low-level command
	 */
	void syncEnd();
	void animeEnd();

signals:
	/**
	 * @brief visualize requested
	 * @param variableName the variable to be visualized
	 */
	void visualize( const QString & variableName );
	/**
	 * @brief update requested
	 */
	void update();
	/**
	 * @brief animation requested
	 * @param variableName the variable to be animated
	 */
	void anime( const QString & variableName );

private:
	CommandServer();
	CommandServer( const CommandServer & );
	CommandServer & operator =( const CommandServer & );
	virtual ~CommandServer();

	class Private;
	friend class Private;
	std::shared_ptr< Private > p_;
};

#endif
